package com.jiamingZhao.proxy;

import cn.hutool.core.util.StrUtil;
import com.jiamingZhao.annotations.Select;
import com.jiamingZhao.annotations.TableName;
import com.jiamingZhao.cache.CacheMap;
import com.jiamingZhao.config.DataSourceConfig;
import com.jiamingZhao.enums.FiledType;
import com.jiamingZhao.mapper.base.MPBaseMapper;
import com.jiamingZhao.pojo.entity.base.BaseEntity;
import com.jiamingZhao.utils.DbUtil;
import com.jiamingZhao.utils.ListKit;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

/**
 * @author ：JiaMing Zhao
 * @since ：2025/6/3 17:50
 * @description 自己实现Mapper代理，非构建器模式
 */
@Slf4j
public class MapperProxyMyselfFactory {




     public static <T extends MPBaseMapper<?>>  T getProxy(Class<T> clazz){
        //获取实体类型
         Class<?> entityClazz = DbUtil.getMapperEntityType(clazz);
         String entityClazzName = entityClazz.getSimpleName();
         String tableName = Optional.ofNullable(entityClazz.getAnnotation(TableName.class))
                 .map(TableName::value).orElse(entityClazzName);
         String underlineEntityClazzName = StrUtil.toUnderlineCase(entityClazzName);
         System.out.println(underlineEntityClazzName);

         @SuppressWarnings("unchecked")
         T t = (T) Proxy.newProxyInstance(MapperProxyMyselfFactory.class.getClassLoader(), new Class[]{clazz}, (proxy, method, args) -> {

             String sql = Optional.ofNullable(method.getAnnotation(Select.class))
                     .map(Select::value)
                     .orElse("");
             String MethodName = method.getName();
             Object entity = createInstance(entityClazz);
             Map<String, Method> methodsMap = CacheMap.getEntityMethods(entityClazz);
             String fieldStr = ListKit.getFieldStr(methodsMap.keySet(), Function.identity(), StrUtil.COMMA);
             getById(args, MethodName, sql, fieldStr, tableName, entity, methodsMap);
             return entity;
         });
         return t;
     }

    private static void getById(Object[] args, String MethodName, String sql, String fieldStr, String tableName, Object entity, Map<String, Method> methodsMap) {
        if (MethodName.equals("getById") && StrUtil.isBlank(sql)) {
            sql = "SELECT {} FROM {} WHERE id = '{}'";
            String filledSQL = StrUtil.format(sql, fieldStr, tableName, args[0]);
            log.warn("执行SQL记录：{}", filledSQL);
            Optional.ofNullable(DataSourceConfig.getConnection())
                    .ifPresentOrElse(
                            conn -> {
                                try {
                                    PreparedStatement prepared = conn.prepareStatement(filledSQL);
                                    ResultSet rs = prepared.executeQuery();
                                    //处理结果集的代码
                                    //通过set方法进行赋值。
                                    while (rs.next()) {
                                        FiledType.fillEntityFiled(entity, methodsMap, rs);
                                    }
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            },
                            () -> System.err.println("无法获取数据库连接")
                    );
        }
    }



    private static void fillEntityFiled(Map<String, String> fieldMap, Class<?> entityClazz, Object entity, ResultSet rs) {
        fieldMap.keySet().forEach(fieldName -> {
            String underlineFieldName = fieldMap.get(fieldName);
            try {
                Field field = entityClazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                Class<?> fieldType = field.getType();
                FiledType filedType = FiledType.getFiledType(fieldType);
                if (filedType != null) {
                     field.set(entity, filedType.getResultValue(rs, fieldType, underlineFieldName));
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }

    private static void fillBaseFiled(Map<String, String> baseFiledMap, Object entity, ResultSet rs) {
        baseFiledMap.keySet()
                .forEach(fieldName -> {
                    try {
                        String underlineCase = baseFiledMap.get(fieldName);
                        Field field = BaseEntity.class.getDeclaredField(fieldName);
                        field.setAccessible(true);
                        Class<?> type = field.getType();
                        FiledType filedType = FiledType.getFiledType(type);
                        if (filedType != null) {
                            field.setAccessible(true);
                            field.set(entity, filedType.getResultValue(rs, type, underlineCase));
                        }
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                });
    }


    public static <T> T createInstance(Class<T> clazz) throws Exception {
        // 获取无参构造方法
        Constructor<T> constructor = clazz.getDeclaredConstructor();
        // 设置可访问（如果构造方法是私有的）
        constructor.setAccessible(true);
        // 创建实例
        return constructor.newInstance();
    }

}
